package br.ufrj.dcc.smarthotel.controls;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;


public class ControlNetworkUtil {
	private DefaultHttpClient client = new DefaultHttpClient();
	private static ControlNetworkUtil instance = null;

	private ControlNetworkUtil() {
		//prevent instatiation
	}
	
	public static ControlNetworkUtil getInstance() {
		if(instance == null) {
			instance = new ControlNetworkUtil();
		}
		return instance;
	}
	
	public boolean doDelete (String url) throws ClientProtocolException, IOException {
		HttpClient httpclient = this.client;
		HttpDelete httpDelete = new HttpDelete(url);
        
        HttpParams params = new BasicHttpParams();
        params.setParameter("http.protocol.handle-redirects", false);
        httpDelete.setParams(params);
        
        HttpResponse response = httpclient.execute(httpDelete);
        
        final int statusCode = response.getStatusLine().getStatusCode();

		if (statusCode != HttpStatus.SC_CREATED) {
			Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url);
			return false;
		}
		else {
			return true;
		}
	}
	
	public String doPost (String url, Map<String, Object> kvPairs) throws ClientProtocolException, IOException {
		HttpClient httpclient = this.client;
        HttpPost httpPost = new HttpPost(url);
        
        HttpParams params = new BasicHttpParams();
        params.setParameter("http.protocol.handle-redirects", false);
        httpPost.setParams(params);
        
        if (kvPairs != null && kvPairs.isEmpty() == false) 
        {
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(kvPairs.size());
            
            String k;
            Object v;
            
            Gson gson = new GsonBuilder().serializeNulls().create();
            
            Iterator<String> itKeys = kvPairs.keySet().iterator();
            
            while (itKeys.hasNext())
            {
                k = itKeys.next();
                v = kvPairs.get(k);
                
                nameValuePairs.add(new BasicNameValuePair(k, gson.toJson(v)));
            }
            
            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
        }
        
        HttpResponse response = httpclient.execute(httpPost);
        
        final int statusCode = response.getStatusLine().getStatusCode();

		if (statusCode != HttpStatus.SC_CREATED) {
			Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url);
			return null;
		}
		else {
			Header locationHeader = response.getFirstHeader("Location");
	        return locationHeader.getValue();
		}
	}
	
	public Object retrieve(String url, Type objectClass) {

		HttpGet getRequest = new HttpGet(url);

		try {
			HttpResponse response = this.client.execute(getRequest);
			HttpEntity responseEntity = response.getEntity();
			
			String json = EntityUtils.toString(responseEntity);
			
			final int statusCode = response.getStatusLine().getStatusCode();

			if (statusCode != HttpStatus.SC_OK) {
				Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url);
				return null;
			}
			
			Gson gson = new Gson();
			Object object = gson.fromJson(json, objectClass);
			
			return object;
		} 
		catch (IOException e) {
			getRequest.abort();
			Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
		}

		return null;
	}
	
	public InputStream retrieveStream(String url) {

		HttpGet getRequest = new HttpGet(url);

		try {

			HttpResponse getResponse = client.execute(getRequest);
			final int statusCode = getResponse.getStatusLine().getStatusCode();

			if (statusCode != HttpStatus.SC_OK) { 
				Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url); 
				return null;
			}

			HttpEntity getResponseEntity = getResponse.getEntity();
			return getResponseEntity.getContent();

		} 
		catch (IOException e) {
			getRequest.abort();
			Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
		}

		return null;

	}
	
	public Bitmap retrieveBitmap(String url) throws Exception {

		InputStream inputStream = null;
		try {
			inputStream = this.retrieveStream(url);
			final Bitmap bitmap = BitmapFactory.decodeStream(new FlushedInputStream(inputStream));
			return bitmap;
		} 
		finally {
			this.closeStreamQuietly(inputStream);
		}

	}
	
	public void closeStreamQuietly(InputStream inputStream) {
		try {
			if (inputStream != null) {
				inputStream.close();  
			}
		} catch (IOException e) {
			// ignore exception
		}
	}
}
